import json
from decimal import Decimal

from alipay import AliPay
from django.conf import settings
from django.db import transaction
from django.http import JsonResponse

from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.orders import get_cart_selected_dict, del_cart_selected_sku
from utils.tools import tools
from utils.views import LoginRequiredJSONMixin
from django.views import View


# 1. 展示结算页面数据的类试图
class OrderSettlementView(LoginRequiredJSONMixin, View):
    def get(self, request):
        user = request.user
        # 1. 去数据库中查询当前用户的收货地址
        # address_set = Address.objects.filter(user=user)
        address_set = user.address_set.filter(is_deleted=False)

        # 2. 转成前端想要的格式
        addresses = []
        for address in address_set:
            addresses.append(address.to_dict())

        # 3. 查redis中已勾选的购物车数据
        carts = get_cart_selected_dict(user)  # {16: 2}

        # 4. 转换成前端想要的格式
        skus = []
        total_price = Decimal(0)
        for (sku_id, count) in carts.items():
            try:
                sku = SKU.objects.get(id=sku_id)
            except SKU.DoesNotExist:
                continue
            sku_dict = sku.to_dict()
            sku_dict['count'] = count
            skus.append(sku_dict)
            total_price += count * sku.price

        # 5. 计算运费 < 80 收10块  >= 80 免费
        if total_price < 80:
            freight = Decimal(10)
        else:
            freight = Decimal(0)
        # 6. 返回结果
        context = {
            'addresses': addresses,
            'skus': skus,
            'freight': freight,
            'total_price': total_price
        }
        return JsonResponse(
            {'code': 0, 'errmsg': 'ok', 'context': context})


# 2. 生成订单的类试图
class OrderCommitView(LoginRequiredJSONMixin, View):
    def post(self, request):
        user = request.user
        # 1. 接收参数
        req_str = request.body.decode()
        req_dict = json.loads(req_str)
        address_id = req_dict.get('address_id')
        pay_method = req_dict.get('pay_method')  # 1 货到付款 2 支付宝

        # 2. 校验参数
        # 2.1 参数不能为空
        if not all([address_id, pay_method]):
            return JsonResponse({'code': 400, 'errmsg': '参数不能为空'})
        # 2.2 address_id对应的地址必须存在，而且是当前用户的
        try:
            address = Address.objects.get(id=address_id, user=user)
        except Exception:
            return JsonResponse({'code': 400, 'errmsg': '用户没有该地址'})
        # 2.3 判断支付方式是否合法
        if pay_method not in list(OrderInfo.PAY_METHODS_ENUM.values()):
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        # 开启事务
        try:
            with transaction.atomic():
                # 3. 构把数据插入到订单主表中
                # 3.1 生成一个订单id
                order_id = tools.get_order_id()
                # 3.2 把数据插入到订单表中
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal(0),
                    freight=Decimal(0),
                    pay_method=pay_method
                )

                # 4. 去购物车中把勾选的商品查出来
                carts = get_cart_selected_dict(user)
                # print(carts)  # {2: 6, 1:5}

                # 5. 把数据插入到明细表中
                total_count = 0  # 商品总数
                total_amount = Decimal(0) # 商品总价
                for (sku_id, count) in carts.items():
                    while True:
                        try:
                            sku = SKU.objects.get(id=sku_id)
                        except SKU.DoesNotExist:
                            continue

                        origin_stock = sku.stock

                        if(origin_stock < count): # 判断库存够不够
                            raise RuntimeError('库存不够')

                        # import time
                        # time.sleep(10)

                        sku_stock = origin_stock - count
                        affect_count = SKU.objects.filter(
                            id=sku_id, stock=origin_stock).update(stock=sku_stock)

                        if affect_count ==0:
                            continue

                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=count,
                            price=sku.price,
                        )
                        total_count += count # 累加商品总数
                        total_amount += count * sku.price # 累加商品总价

                        break

                # 6. 对商品的主表信息做修改
                order.total_count = total_count
                order.total_amount = total_amount
                if total_amount < 80:
                    order.freight = Decimal(10)
                order.save()
        except Exception as err:
            return JsonResponse({'code':400, 'errmsg': str(err)})

        # 7. 删除购物车中的数据
        del_cart_selected_sku(user)

        # 8. 返回结果
        return JsonResponse({
            'code': 0, 'errmsg': 'ok', 'order_id':order_id})


# 3. 生成支付链接的类视图
class PaymentView(LoginRequiredJSONMixin, View):
    def get(self, request, order_id):
        user = request.user
        # 1. 查询订单id对应的订单
        try:
            order = OrderInfo.objects.get(order_id=order_id, user=user)
        except:
            return JsonResponse({'code': 400, 'errmsg': '订单不存在'})

        # 2. 创建一个AliPay的对象
        with open(settings.APP_PRIVATE_KEY_PATH, encoding='utf-8') as f:
            app_private_key_string = f.read()
        with open(settings.ALIPAY_PUBLIC_KEY_PATH, encoding='utf-8') as f:
            alipay_public_key_string = f.read()
        alipay = AliPay(
            appid= settings.ALIPAY_APPID,
            app_notify_url=None,
            app_private_key_string=app_private_key_string,
            alipay_public_key_string=alipay_public_key_string,
        )

        # 3. 通过AliPay对象得到支付宝的支付的相关参数
        total_amount = str(order.total_amount + order.freight)
        order_string =  alipay.api_alipay_trade_page_pay(
            subject='美多商城-{}'.format(order.order_id),
            out_trade_no=order.order_id,
            total_amount=total_amount,
            return_url=settings.ALIPAY_RETURN_URL
        )

        # 4， 拼接支付宝的支付地址
        # print(order_string)
        alipay_url = settings.ALIPAY_URL + '?' + order_string
        # 5. 返回结果

        return JsonResponse({'code': 0, 'errmsg': 'ok', 'alipay_url': alipay_url})
